{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "IN_COLAB = 'google.colab' in sys.modules\n",
    "if IN_COLAB:\n",
    "    !git clone https://github.com/cs357/demos-cs357.git\n",
    "    !mv demos-cs357/figures/ .\n",
    "    !mv demos-cs357/additional_files/ ."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "params = {'legend.fontsize': 20,\n",
    "          'figure.figsize': (12, 6),\n",
    "         'axes.labelsize': 20,\n",
    "         'axes.titlesize': 20,\n",
    "         'xtick.labelsize': 20,\n",
    "         'ytick.labelsize': 20,\n",
    "         'lines.linewidth': 3}\n",
    "plt.rcParams.update(params)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1) Let's take a look at the plot for some typical functions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Power functions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 4\n",
    "b = -2\n",
    "x = np.arange(1,1e5)\n",
    "y = a*x**(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.plot(x,y,'-',lw=3) # change to semilogy, semilogx and loglog\n",
    "plt.xlabel('x')\n",
    "plt.ylabel('y')\n",
    "plt.grid(True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exponential function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 4.0\n",
    "b = -1.0\n",
    "x = np.arange(1,100)\n",
    "y = a**(b*x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.plot(x,y,'-', lw=3)   # change to semilogy, semilogx and loglog\n",
    "plt.xlabel('x')\n",
    "plt.ylabel('y')\n",
    "plt.grid(True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## Log functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 4.0\n",
    "b = 1.0\n",
    "x = np.arange(1,100)\n",
    "y = a*np.log(b*x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.plot(x,y,'-', lw=3)  # change to semilogy, semilogx and loglog\n",
    "plt.xlabel('x')\n",
    "plt.ylabel('y')\n",
    "plt.grid(True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2) Algebraic and Exponential Convergence"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## a) Algebraic convergence\n",
    "\n",
    "###  Make some data\n",
    "\n",
    "Let's make 3 pieces of data (these are all power functions):\n",
    "\n",
    "* `error1` might represent error that looks like $e_r\\sim n^{-1}$\n",
    "* `error15` might represent error that looks like $e_r\\sim n^{-1.5}$\n",
    "* `error2` might represent error that looks like $e_r\\sim n^{-2}$\n",
    "\n",
    "### What should this look like in linear, log-linear, and log-log?\n",
    "\n",
    "This is called *algebraic* convergence, with an algebraic index of convergence of $\\alpha = 1.0, 1.5, 2.0$, where\n",
    "$$\n",
    "e_r \\sim n^{-\\alpha}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "n = np.logspace(1, 6, 100) # evenly distribute numbers over logspace\n",
    "\n",
    "error1 = 1 / n**1\n",
    "error15 = 1 / n**1.5\n",
    "error2 = 1 / n**2\n",
    "\n",
    "p = plt.loglog # we use loglog (straight line for power functions)\n",
    "p(n, error1, label=r'$n^{-1}$')\n",
    "p(n, error15, label=r'$n^{-1.5}$')\n",
    "p(n, error2, label=r'$n^{-2}$')\n",
    "\n",
    "plt.xlabel('$n$')\n",
    "plt.ylabel('$e_r$')\n",
    "plt.grid()\n",
    "plt.legend(frameon=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## b) Exponential convergence\n",
    "\n",
    "### Think about *faster* convergence than algebraic\n",
    "\n",
    "Let's make 3 pieces of data:\n",
    "\n",
    "* `error21` might represent error that looks like $e_r\\sim 2^{-n}$\n",
    "* `error23` might represent error that looks like $e_r\\sim 2^{-3n}$\n",
    "* `error2e` might represent error that looks like $e_r\\sim e^{-2n}$\n",
    "\n",
    "### What should this look like?\n",
    "\n",
    "Here the algebraic index is unbounded (the error decays fastter than $n^{-\\alpha}$ for any $\\alpha$).   So we call this **exponential** or **spectral** or a form of **geometric** convergence.\n",
    "\n",
    "That is\n",
    "$$\n",
    "e_r \\sim e^{-\\mu n}\n",
    "$$\n",
    "for some rate $\\mu$ of exponential convergence."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "n = np.logspace(0, 1, 100) # evenly distribute numbers over logspace\n",
    "\n",
    "error21 = 2**-n\n",
    "error23 = 2**-(3*n)\n",
    "error2e  = np.exp(-2*n)\n",
    "\n",
    "p = plt.semilogy # we use semilogy (straight line for exponential functions)\n",
    "p(n, error21, label=r'$2^{-n}$')\n",
    "p(n, error23, label=r'$2^{-3n}$')\n",
    "p(n, error2e, label=r'$e^{-2n}$')\n",
    "\n",
    "plt.xlabel('$n$')\n",
    "plt.ylabel('$e_r$')\n",
    "plt.grid()\n",
    "plt.legend(frameon=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## c) Comparing agebraic and exponential convergences"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "n = np.logspace(0, 2, 100) # evenly distribute numbers over logspace\n",
    "\n",
    "error2e  = np.exp(-2*n)\n",
    "error2 = 1 / n**2\n",
    "\n",
    "#p = plt.plot\n",
    "p = plt.loglog\n",
    "\n",
    "p(n, error2e, label=r'$e^{-2n}$')\n",
    "p(n, error2, label=r'$n^{-2}$')\n",
    "\n",
    "plt.xlabel('$n$')\n",
    "plt.ylabel('error')\n",
    "plt.grid()\n",
    "plt.legend(frameon=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3) Example: Number and Size of Transistors"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Grab some data on transistor size/count\n",
    "\n",
    "https://en.wikipedia.org/wiki/Transistor_count"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from wikitables import import_tables\n",
    "tables = import_tables('Transistor_count')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def getint(value):\n",
    "    try:\n",
    "        return int(value)\n",
    "    except ValueError:\n",
    "        return 0\n",
    "    \n",
    "table = tables[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Parse it\n",
    "\n",
    "This grabs the data from the Wikipedia article  (ignore this if you wish, it is not a pretty implementation anyway, but does the job)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "count = []\n",
    "years = []\n",
    "\n",
    "for r in table.rows:\n",
    "    \n",
    "    # get year\n",
    "    years.append(getint(r['Date ofintroduction'].value))\n",
    "\n",
    "    # get transistor count\n",
    "    c = r['MOS transistor count'].value\n",
    "    if type(c) is int:\n",
    "        count.append(float(c))\n",
    "    else:\n",
    "        split_c = c.replace(',','').split()\n",
    "        if len(split_c) == 0:\n",
    "            count.append(0)\n",
    "        else:\n",
    "            for di in split_c:\n",
    "                if di.isdigit():\n",
    "                    count.append(float(di))\n",
    "                    break\n",
    "                else:\n",
    "                    if di[-1] == \"+\":\n",
    "                        count.append(float(di[:-1]))\n",
    "                        break\n",
    "                        \n",
    "\n",
    "years = np.array(years)\n",
    "count = np.array(count)\n",
    "\n",
    "I = np.where((years!=0) & (count!=0))\n",
    "years = years[I]\n",
    "count = count[I]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Let's plot it!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10,5))\n",
    "plt.plot(years, count, 'o')\n",
    "plt.xlabel('year')\n",
    "plt.ylabel('count')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Is this the *best* way to display the data? What would you change?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10,5))\n",
    "plt.semilogy(years, count, 'o', basey=2)\n",
    "plt.xlabel('year')\n",
    "plt.ylabel('count')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Add a slope line\n",
    "see `polyfit`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10,5))\n",
    "plt.semilogy(years, count, 'o', basey=2)\n",
    "plt.xlabel('year')\n",
    "plt.ylabel('count')\n",
    "\n",
    "p = np.polyfit(years, np.log2(count), 1)\n",
    "plt.plot(years, 2**(np.polyval(p, years)), 'r-')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4) Errors"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Experiment #1\n",
    "\n",
    "Let's take $\\pi$ and round it to a few digits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.pi"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = 3.142"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "aerror = np.abs(a - b)\n",
    "print(aerror)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rerror = np.abs(a - b) / np.abs(a)\n",
    "print(rerror)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Experiment #2\n",
    "\n",
    "Let's try the value of a car, say $\\$18,382.99$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 18382.99"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = 18000.00"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "aerror = np.abs(a - b)\n",
    "print(aerror)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rerror = np.abs(a - b) / np.abs(a)\n",
    "print(rerror)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
